package com.hp.usage.gr.cli;

import com.hp.siu.collector.rules.Rule;
import com.hp.siu.collector.rules.RuleException;
import com.hp.siu.logging.Level;
import com.hp.siu.logging.Logger;
import com.hp.siu.utils.*;
import com.hp.usage.gr.GrBaseRule;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Created by huxiaoji on 1/14/2016.
 */
public class CommandInvokeRule extends GrBaseRule {
    private static Logger log_ = Logger.getLogger("com.hp.usage.gr.cli.CommandInvokeRule", "com.hp.usage.gr.message_catalog");

    private String command, shell, resultCode, stdout, stderr;

    @Override
    public void applyRule(NormalizedMeteredEvent nme, NormalizedMeteredEvent normalizedMeteredEvent1) throws RuleException {
        if (log_.isLoggable(Level.DEBUG4)){
            log_.logDebug4("CommandInvokeRule.applyRule(" + nme + ")");
        }

        try {
            CmdResult result = new CmdResult();
            if (!isEmpty(command)) {
                int status = CmdUtils.runCmdRtnStatus(decodeNME(nme, command), result);

                setResult(nme, status, result.getStdout().toString(), result.getStderr().toString());
            } else {
                int status = CmdUtils.runShellScript(decodeNME(nme, shell), result, false);

                setResult(nme, status, result.getStdout().toString(), result.getStderr().toString());
            }
        } catch (Exception e){
            if (log_.isLoggable(Level.DEBUG4)){
                log_.log(Level.DEBUG4, e.getMessage(), e);
            }
            setResult(nme, -1, "", e.getMessage());
        }

        if (this.next_ != null)
            this.next_.applyRule(nme, normalizedMeteredEvent1);
    }

    private void setResult(NormalizedMeteredEvent nme, int exitCode, String out, String err) {
        if (log_.isLoggable(Level.DEBUG)){
            log_.logDebug("command execute return: " + exitCode + ":" + out + ":" + err);
        }
        if (!isEmpty(resultCode)){
            setAttributesInNME(nme, resultCode, String.valueOf(exitCode));
        }
        if (!isEmpty(stdout)){
            setAttributesInNME(nme, stdout, isEmpty(out)?"":out);
        }
        if (!isEmpty(stderr)){
            setAttributesInNME(nme, stderr, isEmpty(err)?"":err);
        }
    }

    @Override
    public void configure(Config config) throws ConfigurationException {
        if (log_.isLoggable(Level.DEBUG4)){
            log_.logDebug4("CommandInvokeRule.configure()");
        }
        command = config.getAttribute("Command");
        if (isEmpty(command)){
            shell = config.getAttribute("ShellScript");
        }
        if (isEmpty(command) && isEmpty(shell)){
            throw new ConfigurationException("Command and ShellScript shouldn't both empty.");
        }

        resultCode = config.getAttribute("ExitStatusAttribute");
        stdout = config.getAttribute("StdOutTextAttribute");
        stderr = config.getAttribute("StdErrTextAttribute");

        if (log_.isLoggable(Level.DEBUG4)){
            log_.logDebug4("CommandInvokeRule.configure() done: Command: " + command + ", ShellScript: " + shell + ", exitCode: " + resultCode + ", stdout: " + stdout + ", stderr: " + stderr);
        }
    }

    private static final Pattern PATTERN = Pattern.compile("%([A-Za-z1-9_]+)%");
    private String decodeNME(NormalizedMeteredEvent nme, String value){
        Matcher m = PATTERN.matcher(value);
        StringBuffer sb = new StringBuffer();
        while (m.find()){
            String attrName = m.group(1);
            Attribute attr = nme.getAttribute(attrName);
            if (attr == null){
                log_.warning("Can't get attribute " + attrName + " from NME.");
                m.appendReplacement(sb, attrName);
            } else {
                m.appendReplacement(sb, attr.toString());
            }
        }
        m.appendTail(sb);

        if (log_.isLoggable(Level.DEBUG4)){
            log_.logDebug4("command change to " + sb.toString());
        }
        return sb.toString();
    }


}
